vtd: fix interrupt remapping to handle SMI RTE's with uninitialized
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 10 Nov 2008 10:41:41 +0000 (10:41 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 10 Nov 2008 10:41:41 +0000 (10:41 +0000)
reserved fields

Some BIOS does not zero out reserve fields in IOAPIC RTE's.
clear_IO_APIC() zeroes out all RTE's except for RTE with MSI delivery
type.  This is a problem when the host OS converts SMI delivery type
to some other type but leaving the reserved field uninitialized.  This
can cause interrupt remapping table out of bound error if "format"
field is 1 and the uninitialized "index" field has a value that that
is larger than the maximum index of interrupt remapping table.

Signed-off-by: Allen Kay <allen.m.kay@intel.com>=
xen/drivers/passthrough/vtd/dmar.c
xen/drivers/passthrough/vtd/intremap.c

index 43107b3ae345a8af6a0554facf6d24d43de814d3..93531c65a2d6b8e7aa7ebd07883d1b2af04c8870 100644 (file)
@@ -351,7 +351,9 @@ acpi_parse_one_rmrr(struct acpi_dmar_entry_header *header)
 
     if ( rmrr->base_address >= rmrr->end_address )
     {
-        dprintk(XENLOG_ERR VTDPREFIX, "RMRR is incorrect.\n");
+        dprintk(XENLOG_ERR VTDPREFIX,
+                "RMRR error: base_addr %"PRIx64" end_address %"PRIx64"\n",
+                rmrr->base_address, rmrr->end_address);
         return -EFAULT;
     }
 
index 059ebf5a244b95bd9b48341bd489065fc6dd8558..f484a59e39b9c7c3cabd3de4703eecfa5c9bac25 100644 (file)
@@ -207,7 +207,7 @@ unsigned int io_apic_read_remap_rte(
 
     remap_rte = (struct IO_APIC_route_remap_entry *) &old_rte;
 
-    if ( remap_rte->format == 0 )
+    if ( (remap_rte->format == 0) || (old_rte.delivery_mode == dest_SMI) )
     {
         *IO_APIC_BASE(apic) = rte_upper ? (reg + 1) : reg;
         return *(IO_APIC_BASE(apic)+4);
@@ -253,6 +253,31 @@ void io_apic_write_remap_rte(
 
     remap_rte = (struct IO_APIC_route_remap_entry *) &old_rte;
 
+    if ( old_rte.delivery_mode == dest_SMI )
+    {
+        /* Some BIOS does not zero out reserve fields in IOAPIC
+         * RTE's.  clear_IO_APIC() zeroes out all RTE's except for RTE
+         * with MSI delivery type.  This is a problem when the host
+         * OS converts SMI delivery type to some other type but leaving
+         * the reserved field uninitialized.  This can cause interrupt
+         * remapping table out of bound error if "format" field is 1
+         * and the "index" field has a value that that is larger than 
+         * the maximum index of interrupt remapping table.
+         */
+        if ( remap_rte->format == 1 )
+        {
+            remap_rte->format = 0;
+            *IO_APIC_BASE(apic) = reg;
+            *(IO_APIC_BASE(apic)+4) = *(((u32 *)&old_rte)+0);
+            *IO_APIC_BASE(apic) = reg + 1;
+            *(IO_APIC_BASE(apic)+4) = *(((u32 *)&old_rte)+1);
+        }
+
+        *IO_APIC_BASE(apic) = rte_upper ? (reg + 1) : reg;
+        *(IO_APIC_BASE(apic)+4) = value;
+        return;
+    }
+
     /* mask the interrupt while we change the intremap table */
     saved_mask = remap_rte->mask;
     remap_rte->mask = 1;